#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/1/7 12:39
# @Author  : 新猿异码
# @Site    : https://gitee.com/chshao/autotest
# @CSDN    : https://blog.csdn.net/m0_37576542?type=blog
# @File    : PopenOS.py
# @Desc    : 命令行指令运行模块
# @Software: PyCharm
import time
import datetime
import queue
import subprocess
import threading
from typing import Union


class Popen(threading.Thread):
    _queue = queue.Queue()
    end_mark = f"popen end:{datetime.datetime.now().strftime('%Y%m%d_%H%M%S_%f')}"

    def __init__(self, args: Union[str, list], bufsize=1, shell=True, callback=None, stop_symbol=None, daemonic=False):
        """
        :param args: 待执行的命令
        :param bufsize: bufsize=0时，为不缓存；bufsize=1时，按行缓存；bufsize为其他正整数时，为按照近似该正整数的字节数缓存
        :param shell:
        :param callback: 当有信息输出时的回调函数
        :param stop_symbol: 停止标志，当出现次结束符时强行杀死子进程
        :param daemonic: 是否设置为守护进程，若果是，则主进程结束子进程也会结束，否则相反
        """
        threading.Thread.__init__(self)
        self.args = args
        self.bufsize = bufsize
        self.shell = shell
        self.cwd = './'
        self.stop_symbol = stop_symbol
        self.callback = callback
        self.proc = None
        self.setDaemon(daemonic)
        self.start()

    def run(self):
        self.proc = subprocess.Popen(self.args,
                                     bufsize=self.bufsize,
                                     shell=self.shell,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.STDOUT,
                                     text=True,  # 缓存内容为文本，避免后续编码显示问题
                                     encoding='utf-8',
                                     errors='ignore',
                                     cwd=self.cwd  # 这个参数意思是，当前子进程结束后，其结果保存地址
                                     )

        while self.proc.poll() is None:
            line = self.proc.stdout.readline()
            if line:
                self._queue.put_nowait(line)  # TODO:需要增加队列满了的处理逻辑
                # 刷新缓存，防止缓存过多造成卡死
                self.proc.stdout.flush()
                # 调用回调函数
                if self.callback:
                    self.callback(line)
                # 出现停止标志，杀死进程
                if self.stop_symbol is not None:
                    if self.stop_symbol in line:
                        self.proc.terminate()
                        break
        self._queue.put_nowait(self.end_mark)

    def terminate(self):
        self.proc.terminate()

    def read_until_end(self, timeout=60):
        """
        一直读取，直到子进程结束
        :param timeout: 超时时间
        :return:
        """
        msg_all = []
        end_time = time.time() + timeout
        while time.time() < end_time:
            if self._queue.empty():
                time.sleep(0.1)
                continue
            msg = self._queue.get_nowait()
            msg_all.append(msg)
            if self.end_mark == msg:
                return True, msg_all
        print("超时未结束！")
        return False, msg_all

    def wait_until_end(self, timeout=60) -> bool:
        """
        等待子进程结束
        :param timeout: 超时时间
        :return:
        """
        end_time = time.time() + timeout
        while time.time() < end_time:
            if self._queue.empty():
                time.sleep(0.1)
                continue
            msg = self._queue.get_nowait()
            if self.end_mark == msg:
                return True
        print("超时未结束！")
        return False

    def read_until(self, keyword: str, timeout=60):
        """
        一直读取，直到关键字出现
        :param keyword: 关键字，不区分大小写
        :param timeout: 超时时间
        :return:
        """
        msg_all = []
        end_time = time.time() + timeout
        while time.time() < end_time:
            if self._queue.empty():
                time.sleep(0.1)
                continue
            msg = self._queue.get_nowait()
            msg_all.append(msg)
            if keyword.lower() in msg.lower():
                return True, msg_all
        print(f"超时未出现关键字: {keyword}！")
        return False, msg_all

    def wait_until(self, keyword: str, timeout=60) -> bool:
        """
        一直等待，直到关键字出现
        :param keyword: 关键字，不区分大小写
        :param timeout: 超时时间
        :return:
        """
        end_time = time.time() + timeout
        while time.time() < end_time:
            if self._queue.empty():
                time.sleep(0.1)
                continue
            msg = self._queue.get_nowait()
            if keyword.lower() in msg.lower():
                return True
        print(f"超时未出现关键字: {keyword}！")
        return False


if __name__ == '__main__':
    cmd = [
        "adb",
        "-s",
        "3LGGK17609000012",
        "shell",
        "LD_LIBRARY_PATH=/data/local/tmp",
        "/data/local/tmp/minicap",
        "-P",
        "1080x1920@1080x1920/0"
    ]
    # cmd = "adb shell ps | findstr minicap"
    testProcess = Popen(cmd, shell=True, callback=None)
    print(testProcess.read_until(keyword="Server start"))
